/*
 * Copyright (c) 2022  by Junzhao
 * THIS FILE IS PART OF JAVASE Song Huongkang PROJECT
 * All Rights Reserved.
 */

package 函数式接口;

import org.junit.Test;

import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

/**
 * @Description 函数式接口
 * 只包含一个抽象方法的接口，称为 函数式接口 。
 * 你可以通过 Lambda 表达式来创建该接口的对象。（若 Lambda 表达式
 * 抛出一个受检异常 即：非运行时异常 ))，那么该异常需要在目标接口的抽
 * 象方法上进行声明）。
 * 我们可以在一个接口上使用 FunctionalInterface 注解，这样做可以检
 * 查它是否是一个函数式接口。同时 javadoc 也会包含一条声明，说明这个
 * 接口是一个函数式接口。
 * 在 java.util.function 包下定义 了 Java 8 的丰富的函数式 接口
 * Java 从诞生日起就是一直倡导“一切皆对象”， 在 Java 里面面向对象 (
 * 编程是一切。但是随着 python 、 scala 等语言的兴起和新技术的挑战 Java 不
 * 得不做出调整以便支持更加广泛的技术要求，也即 java 不但可以支持 OOP 还
 * 可以支持 OOF （面向函数编程
 * 在函数式编程语言当中，函数被当做一等公民对待。在将函数作为一等公民的
 * 编程语言中， Lambda 表达式的类型是函数。但是在 Java8 中，有所不同。在
 * Java8 中， Lambda 表达式是对象，而不是函数，它们必须依附于一类特别的
 * 对象类型 函数式接口 。
 * 简单的说，在 Java8 中， Lambda 表达式就是一个函数式接口的实例。 这就是
 * Lambda 表达式和函数式接口的关系。也就是说，只要一个对象是函数式接口
 * 的实例，那么该对象就可以用 Lambda 表达式来表示。
 * 所以以前用 匿名实现类 表示的现在都可以用 Lambda 表达式来写。
 * @Author 俊昭
 * @Date 2022/5/11
 */
public class FunctionalInterfaceTest {
    /**
     * \\@FunctionalInterface
     * public interface Comparator<T> {
     * <p>
     * \\@FunctionalInterface
     * public interface Runnable {
     * 以上两个都是函数式接口
     * \@since 1.8
     * \@Documented
     * \@Retention(RetentionPolicy.RUNTIME)
     * \@Target(ElementType.TYPE)
     * public @interface FunctionalInterface {
     */
    @Test
    public void test001() {
        // 自定义的函数式接口
        MyInterface i1 = () -> System.out.println("我是函数式接口");

        i1.method1();
        // 我是函数式接口
    }
    /**
     * 内置的四大函数式接口
     */
    @Test
    public void test002(){
        // 一 消费型接口 Consumer<T> 对类型为T 的对象应用操作，包含 方法void accept(T t)
        Consumer<String> consumer = s -> System.out.println(s+"消费型接口") ;
        consumer.accept("1");
        // 1消费型接口

        // 二 供给型接口 Supplier<T> 返回类型为T 的对象，包含 方法 T get()
        Supplier<String> supplier = () -> "供给型接口";
        System.out.println(supplier.get());
        // 供给型接口

        // 三 函数型接口 Function<T, R> 对类型为T 的对象应用操作，并返回结果。结果是 R 类型的对象。包含 方法 R apply(T t)
        Function<Integer,Double> findArea = r -> r*r*Math.PI;
        System.out.println(findArea.apply(2));
        //12.566370614359172

        // 四 断定型接口 Predicate<T>  确定类型为T 的对象是否满足某约束，并返回boolean 值。包含 方法 boolean test(T t)

        Predicate<int[]> isContain = arr -> {
            boolean flag;
            for (int j : arr) {
                flag = j == 5;
                if (flag) {
                    return true;
                }
            }
            return false;
        };

        System.out.println(isContain.test(new int[]{1, 2, 3, 4, 5}));
        System.out.println(isContain.test(new int[]{1, 2, 3, 4}));
        // true
        // false


    }
}
@FunctionalInterface
interface MyInterface{
    void method1();
//    void method2();在接口 函数式接口.MyInterface 中找到多个非重写 abstract 方法
}